/**
 * Alipay.com Inc. Copyright (c) 2004-2018 All Rights Reserved.
 */
package com.yeyks.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.yeyks.apppay.service.AlipayService;
import com.yeyks.apppay.service.WXAppPayService;
import com.yeyks.base.Arguments;
import com.yeyks.base.PageInfo;
import com.yeyks.constant.ConfigKey;
import com.yeyks.constant.MessageTemplate;
import com.yeyks.dal.dao.AccountInfoMapper;
import com.yeyks.dal.dao.OrderInfoMapper;
import com.yeyks.dal.dao.RoomInfoMapper;
import com.yeyks.dal.dao.UserCouponInfoMapper;
import com.yeyks.dal.domain.*;
import com.yeyks.dto.OrderDetailDTO;
import com.yeyks.dto.OrderInfoDTO;
import com.yeyks.exception.ServiceException;
import com.yeyks.getui.service.GeTuiService;
import com.yeyks.model.CouponConst;
import com.yeyks.model.OrderStatus;
import com.yeyks.model.PreOrderInfo;
import com.yeyks.model.enums.PayTypeEnum;
import com.yeyks.rabbitmq.send.OrderQueueMsg;
import com.yeyks.service.*;
import com.yeyks.util.*;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.google.common.collect.Lists;
import com.yeyks.service.AccountService;
import com.yeyks.service.OrderService;
import com.yeyks.service.PayService;
import com.yeyks.service.SmsService;
import com.yeyks.util.Utility;
import com.yeyks.wxcode.service.WxLoginService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author Beacon
 * @version $Id: OrderServiceImpl.java, v 0.1 2018年08月27日 20:20 Beacon Exp $
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private AccountInfoMapper accountInfoMapper;

    @Autowired
    private SmsService smsService;

    @Autowired
    private RoomInfoMapper roomInfoMapper;

    @Autowired
    private RoomInfoService roomInfoService;

    @Autowired
    private HotelService hotelService;

    @Autowired
    private CouponInfoService couponInfoService;

    @Autowired
    private UserCouponService userCouponService;

    @Autowired
    private AccountService accountService;

    @Autowired
    private AlipayService alipayService;

    @Autowired
    private WXAppPayService wxAppPayService;

    @Autowired
    private PayService payService;

    @Autowired
    private OrderQueueMsg orderQueueMsg;

    @Autowired
    private ConfigService configService;

    @Autowired
    private MessageNoticeService noticeService;

    @Autowired
    private MessageNoticeTemplateService templateService;

    @Autowired
    private UserCouponInfoMapper userCouponInfoMapper;

    @Autowired
    private GeTuiService geTuiService;

    @Value("${wx.pay.oldNotifyUrl}")
    private String oldNotifyUrl;

    /**
     * 共享读写锁
     */
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * 缓存的预支付信息
     */
    private Map<String, PreOrderInfo> preOrderInfoMap = new HashMap<>();

    @Override
    public void insertPreOrder(PreOrderInfo preOrderInfo) {
        try {
            lock.writeLock().lock();
            preOrderInfoMap.put(preOrderInfo.getOrderInfo().getOrderNo(), preOrderInfo);
        } finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public PreOrderInfo getPreOrderInfo(String orderNo) {

        PreOrderInfo preOrderInfo = null;
        try {
            lock.writeLock().lock();

            preOrderInfo = preOrderInfoMap.get(orderNo);
        } finally {
            lock.writeLock().unlock();
        }

        return preOrderInfo;
    }

    @Override
    public boolean chargeSucceededOrder(String orderNo) {

        boolean ret = false;
        try {
            lock.writeLock().lock();

            PreOrderInfo preOrderInfo = preOrderInfoMap.get(orderNo);

            if (preOrderInfo != null) {
                preOrderInfo.getOrderInfo().setStatus(OrderStatus.preCheckIn);

                ret = true;
            }
        } finally {
            lock.writeLock().unlock();
        }

        return ret;
    }

    @Override
    public void deleteInfo(String orderNo) {
        try {
            lock.writeLock().lock();

            preOrderInfoMap.remove(orderNo);
        } finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public String getTopOrderNo() {
        Set<String> keySet = preOrderInfoMap.keySet();
        for (String key : keySet) {
            return key;
        }

        return null;
    }

    @Override
    @Transactional
    public Boolean payCallback(String orderNo, Boolean succeeded) {
        PreOrderInfo preOrderInfo = getPreOrderInfo(orderNo);
        if (preOrderInfo != null) {
            OrderInfo orderInfo = preOrderInfo.getOrderInfo();
            RoomInfo roomInfo = preOrderInfo.getRoomInfo();
            Integer count = preOrderInfo.getCount();
            log.info("更新之前" + JSONObject.toJSON(orderInfo));
            orderInfo.setStatus(succeeded ? OrderStatus.preCheckIn : OrderStatus.payFailed);
            Integer userCouponId = getUserCouponId(orderInfo);
            if (succeeded) {
                //如果入住时间是今日，并且过了18点，则修改为已经入住
                int day = DateUtils.toLocalDate(orderInfo.getCheckIn()).getDayOfMonth();
                int nowDay = LocalDate.now().getDayOfMonth();
                //减少房间个数
                if (day == nowDay) {
                    lessRoomCount(roomInfo, count);
                    if (DateUtils.afterHour(getCheckInHour())) {
                        orderInfo.setStatus(OrderStatus.living);
                    }
                }
                //修改券的使用状态
                if (userCouponId != null && userCouponId != 0) {
                    userCouponService.updateCouponUseById(userCouponId, true);
                }
                //给酒店发送订单通知
                sendToHotel(preOrderInfo);
                //给用户发送短信
                smsOrderComplate(preOrderInfo);
                //记录订单成功通知
                messageNotice(preOrderInfo);
                //个推推送
                geTuiMessage(preOrderInfo);
                //websocket消息推送
                sendMessage(preOrderInfo);
            }
            log.info("更新之后" + JSONObject.toJSON(orderInfo));
            if (preOrderInfo.getOrderInfo().getId() == null) {
                orderInfoMapper.insert(preOrderInfo.getOrderInfo());
            } else {
                orderInfoMapper.updateByPrimaryKey(preOrderInfo.getOrderInfo());
            }
            if (succeeded) {
                deleteInfo(orderNo);
            }
            return true;
        }
        return false;
    }

    private void geTuiMessage(PreOrderInfo preOrderInfo) {
        try {
            OrderInfo orderInfo = preOrderInfo.getOrderInfo();
            String title = "您有新订单到了!";
            String content = orderInfo.getOrderNo();
            geTuiService.singlePush(String.valueOf(orderInfo.getUserId()), title, JSONObject.toJSONString(getMap(title, content)));
        } catch (Exception e) {
            log.error("个推消息失败{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

    private Map<String, String> getMap(String title, String content) {
        Map<String, String> map = new HashMap<>();
        map.put("title", title);
        map.put("content", content);
        return map;
    }

    private void messageNotice(PreOrderInfo preOrderInfo) {
        try {
            OrderInfo orderInfo = preOrderInfo.getOrderInfo();
            HotelInfo hotelInfo = preOrderInfo.getHotelInfo();
            String checkIn = DateUtils.toYYMMddStr(orderInfo.getCheckIn());
            String checkOut = DateUtils.toYYMMddStr(orderInfo.getCheckOut());
            String hotelName = hotelInfo.getName();
            Integer count = DateUtils.getDayByBeginEnd(orderInfo.getCheckIn(), orderInfo.getCheckOut()).intValue();
            Map<String, String> map = templateService.orderAfterHandleValue(MessageTemplate.ORDER_ACCEPT, hotelName, checkIn, checkOut, count);
            noticeService.createNoticeAndSave(map, orderInfo.getUserId(), hotelInfo.getId());
        } catch (Exception e) {
            log.error("生成订单成功消息失败{}", e.getLocalizedMessage());
        }
    }

    private Integer getCheckInHour() {
        try {
            String value = configService.getValue(ConfigKey.ORDER_CHECKIN);
            JSONObject jsonObject = JSONObject.parseObject(value);
            return (Integer) jsonObject.get("checkin");
        } catch (Exception e) {
            log.error("查询订单checkIn失败{}", e.getLocalizedMessage());
            return 18;
        }
    }

    private void lessRoomCount(RoomInfo roomInfo, Integer count) {
        try {
            lock.writeLock().lock();
            Integer available = roomInfo.getAvailable();
            if (count != null) {
                if (available != null && available >= count) {
                    available -= count;
                }
                roomInfo.setAvailable(available);
                roomInfoMapper.updateIfNotNullByPrimaryKey(roomInfo);
            }
        } catch (Exception e) {
            log.error("回调出错{}", e.getLocalizedMessage());
        } finally {
            lock.writeLock().unlock();
        }
    }

    private void sendMessage(PreOrderInfo preOrderInfo) {
        HotelInfo hotelInfo = preOrderInfo.getHotelInfo();
        if (hotelInfo == null) {
            return;
        }
        AccountInfo accountInfo = accountInfoMapper.selectByPrimaryKey(hotelInfo.getOperatorId());
        if (accountInfo == null) {
            return;
        }
        try {
            //通过酒店id获取酒店上级用户名
            List<Integer> userIds = accountInfoMapper.selectAllParentId(accountInfo.getId());
            for (Integer userId : userIds) {
                if (userId == null) {
                    continue;
                }
                Map<String, String> map = new HashMap<>();
                map.put("message", preOrderInfo.getOrderInfo() == null ? null : preOrderInfo.getOrderInfo().getOrderNo());
                map.put("userId", String.valueOf(userId));
                orderQueueMsg.send(JSONObject.toJSONString(map));
                orderQueueMsg.sendToB(preOrderInfo.getOrderInfo());
            }
        } catch (Exception e) {
            log.error("订单回调推送消息异常{}", e.getLocalizedMessage());
        }
    }

    private void sendToHotel(PreOrderInfo preOrderInfo) {
        try {
            OrderInfo orderInfo = preOrderInfo.getOrderInfo();
            RoomInfo roomInfo = preOrderInfo.getRoomInfo();
            HotelInfo hotelInfo = preOrderInfo.getHotelInfo();
            //查询酒店方手机号
//            String phone = hotelService.getSmsPhoneByHotelInfo(hotelInfo);
            String phone = hotelInfo.getPhone();
            Map<String, String> map = getNamePhone(orderInfo);
            String person = map.get("name");
            String daytime = DateUtils.toYYMMddStr(orderInfo.getCheckIn());
            String hotelname = hotelInfo.getName();
            String roomtype = roomInfo.getTitle();
            String roomnum = String.valueOf(preOrderInfo.getCount());
            String roomnight = String.valueOf(DateUtils.getDayByBeginEnd(orderInfo.getCheckIn(), orderInfo.getCheckOut()));
            smsService.sendSmsToHotelForOrderComplete(phone, person, daytime, hotelname, roomtype, roomnum, roomnight);
        } catch (Exception e) {
            log.info("订单回调给酒店方发短信异常{}", e.getLocalizedMessage());
        }

    }

    private void smsOrderComplate(PreOrderInfo preOrderInfo) {
        try {
            OrderInfo orderInfo = preOrderInfo.getOrderInfo();
            RoomInfo roomInfo = preOrderInfo.getRoomInfo();
            HotelInfo hotelInfo = preOrderInfo.getHotelInfo();
            Map<String, String> map = getNamePhone(orderInfo);
            String phone = map.get("phone");
            String person = map.get("name");
            String daytime = DateUtils.toYYMMddStr(orderInfo.getCheckIn());
            String hotelname = hotelInfo.getName();
            String roomtype = roomInfo.getTitle();
            String roomnum = String.valueOf(preOrderInfo.getCount());
            String roomnight = String.valueOf(DateUtils.getDayByBeginEnd(orderInfo.getCheckIn(), orderInfo.getCheckOut()));
            String address = hotelInfo.getAddress();
            String hoteltel = hotelService.getTelByHotelInfo(hotelInfo);
            smsService.sendSmsToUserForOrderComplete(phone, person, daytime, hotelname, roomtype, roomnum, roomnight, address, hoteltel);
        } catch (Exception e) {
            log.info("订单回调给用户发短信异常{}", e.getLocalizedMessage());
        }
    }

    public String getPhoneByOrderInfo(OrderInfo orderInfo) {
        String phone;
        try {
            JSONObject jsonObject = JSONObject.parseObject(orderInfo.getVitalPersonInfo());
            phone = (String) jsonObject.get("phone");
            return phone;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 通过订单信息获取订单对应用户名和手机号
     *
     * @param orderInfo
     * @return
     */
    @Override
    public Map<String, String> getNameAndPhoneByOrderInfo(OrderInfo orderInfo) {
        Map<String, String> map = new HashMap<>();
        try {
            JSONObject jsonObject = JSONObject.parseObject(orderInfo.getVitalPersonInfo());
            String name = (String) jsonObject.get("name");
            String phone = (String) jsonObject.get("phone");
            map.put("name", name);
            map.put("phone", phone);
            return map;
        } catch (Exception e) {
            log.info("通过订单信息获取下单用户以及手机号失败，orderNo = {}", orderInfo.getOrderNo());
            map.put("name", null);
            map.put("phone", null);
            return map;
        }
    }

    private Integer getUserCouponId(OrderInfo orderInfo) {
        JSONObject jsonObject = JSONObject.parseObject(orderInfo.getExtraInfo());
        return (Integer) jsonObject.get("couponId");
    }

    @Override
    public Boolean refundCallback(String orderNo, Boolean succeeded, Object refundInfo) {
        OrderInfo orderInfo = orderInfoMapper.selectByOrderNo(orderNo);
        if (orderInfo == null) {
            return false;
        } else if (orderInfo.getStatus() != OrderStatus.preCheckIn &&
                orderInfo.getStatus() != OrderStatus.preRefund) {
            return false;
        }

        if (succeeded) {
            orderInfo.setStatus(OrderStatus.postRefund);
        } else if (orderInfo.getStatus() == OrderStatus.preRefund) {
            orderInfo.setStatus(OrderStatus.preCheckIn);
        }

        Integer refundFee = ((WxPayRefundNotifyResult.ReqInfo) refundInfo).getRefundFee();
        JSONObject extraObj = Utility.toJsonObject(orderInfo.getExtraInfo());
        extraObj.put("refund_info", refundInfo);
        extraObj.put("snapshot_refundFee", refundFee);
        orderInfo.setExtraInfo(extraObj.toJSONString());
        orderInfo.setSnapshotRefundFee(refundFee);
        orderInfo.setGmtModified(new Date());
        orderInfoMapper.updateByPrimaryKey(orderInfo);

        return true;
    }

    /**
     * 分页获取订单
     *
     * @param status
     * @param orderNo
     * @param orderDate
     * @param checkIn
     * @param checkOut
     * @param pageNum
     * @param pageSize
     * @param type
     * @return
     */
    @Override
    public Map<String, Object> selectOrderByPage(String status, String orderNo, String orderDate, String checkIn, String checkOut, Integer pageNum, Integer pageSize, Integer type, Integer id) {
        PageInfo pageInfo = PageInfo.of(pageNum, pageSize);
        Map<String, Object> map = new HashMap<>();
        List<Integer> statusList = null;
        if (Arguments.notEmpty(status)) {
            statusList = Splitters.splitToInteger(status, Splitters.COMMA);
        }
//        map.put("status", status);
        map.put("statusList", statusList);
        map.put("orderNo", orderNo);
        Date orderCreateDate = DateUtils.yyyyMMddToDate(orderDate);
        if (orderDate != null) {
            map.put("orderEndDate", DateUtils.afterDaysToDate(orderCreateDate, 1L));
        }
        map.put("orderDate", orderCreateDate);
        map.put("checkIn", checkIn);
        map.put("checkOut", checkOut);
        map.put("offset", pageInfo.getOffset());
        map.put("limit", pageInfo.getLimit());
        map.put("type", type);
        map.put("id", id);
        List<Map> orderInfos = orderInfoMapper.selectOrderByPage(map);
        Long count = orderInfoMapper.selectOrderByPageCount(map);
        map.clear();
        map.put("list", orderInfos);
        map.put("count", count);
        return map;
    }

    /**
     * 查询各状态的订单数
     *
     * @param id
     * @param pageNum
     * @param pageSize
     * @param type     默认1全部，2已付款，3未支付，4已取消
     * @return
     */
    @Override
    public List<OrderInfoDTO> selectOrderList(Integer id, Integer pageNum, Integer pageSize, Integer type) {
        PageInfo pageInfo = PageInfo.of(pageNum, pageSize);
        List<Integer> statusList = null;
        if (type == 2) {
            statusList = new ArrayList<>();
            statusList.add(OrderStatus.preCheckIn);
            statusList.add(OrderStatus.postCheckOut);
            statusList.add(OrderStatus.preRefund);
            statusList.add(OrderStatus.living);
            statusList.add(OrderStatus.comment);
        } else if (type == 3) {
            statusList = new ArrayList<>();
            statusList.add(OrderStatus.prePay);
        } else if (type == 4) {
            statusList = new ArrayList<>();
            statusList.add(OrderStatus.payFailed);
            statusList.add(OrderStatus.postRefund);
            statusList.add(OrderStatus.cancle);
        }
        List<OrderInfo> orderInfos = orderInfoMapper.selectByUser(id, statusList, pageInfo.getOffset(), pageInfo.getLimit());
        if (orderInfos == null || orderInfos.size() == 0) {
            return new ArrayList<>();
        }
        return getOrderInfoDTO(orderInfos);
    }

    private List<OrderInfoDTO> getOrderInfoDTO(List<OrderInfo> orderInfos) {
        Map<Integer, List<String>> roomInfos = getRoomInfos(orderInfos);
        Map<Integer, Integer> hotelIds = getHotelIds(orderInfos);
        List<OrderInfoDTO> list = new ArrayList<>();
        for (OrderInfo orderInfo : orderInfos) {
            OrderInfoDTO orderInfoDTO = ObjectConvertUtil.convertObject(orderInfo, OrderInfoDTO.class);
            JSONObject jsonObject = JSONObject.parseObject(orderInfo.getExtraInfo());
            Integer totalDays = (Integer) jsonObject.get("snapshot_days");
            String telPhone = (String) jsonObject.get("snapshot_tel_phone");
            if (telPhone == null) {
                String hotelPhone = (String) jsonObject.get("snapshot_hotel_phone");
                orderInfoDTO.setHotelPhone(hotelPhone);
            } else {
                orderInfoDTO.setHotelPhone(telPhone);
            }
            orderInfoDTO.setTotalDays(totalDays);
            orderInfoDTO.setRoomUrls(roomInfos.get(orderInfo.getRoomId()));
            orderInfoDTO.setEvaluate(orderInfo.getScore() != null);
            orderInfoDTO.setHotelId(hotelIds.get(orderInfo.getRoomId()));
            list.add(orderInfoDTO);
        }
        return list;
    }

    private Map<Integer, Integer> getHotelIds(List<OrderInfo> orderInfos) {
        Map<Integer, Integer> map = new HashMap<>();
        List<Integer> roomIds = Lists.transform(orderInfos, OrderInfo::getRoomId);
        List<RoomInfo> roomInfos = roomInfoMapper.selectByIds(roomIds);
        for (RoomInfo roomInfo : roomInfos) {
            map.put(roomInfo.getId(), roomInfo.getHotelId());
        }
        return map;
    }

    private Map<Integer, List<String>> getRoomInfos(List<OrderInfo> orderInfos) {
        Map<Integer, List<String>> map = new HashMap<>();
        List<Integer> roomIds = Lists.transform(orderInfos, OrderInfo::getRoomId);
        if (roomIds.size() == 0) {
            return map;
        }
        List<RoomInfo> roomInfos = roomInfoMapper.selectByIds(roomIds);
        for (RoomInfo roomInfo : roomInfos) {
            try {
                JSONObject jsonObject = JSONObject.parseObject(roomInfo.getExtraInfo());
                map.put(roomInfo.getId(), (List<String>) jsonObject.get("imgUrlList"));
            } catch (Exception e) {
                map.put(roomInfo.getId(), new ArrayList<>());
            }
        }
        return map;
    }

    /**
     * 通过订单号查询订单
     *
     * @param orderNo
     * @return
     */
    @Override
    public OrderInfo selectOrderByOrderNo(String orderNo) {

        return orderInfoMapper.selectByOrderNo(orderNo);
    }

    /**
     * 修改订单状态
     *
     * @param orderNo
     * @param status
     * @return
     */
    @Override
    public Integer updateOrderStatus(String orderNo, Integer status) {
        return orderInfoMapper.updateOrderStatus(orderNo, status);
    }

    /**
     * 修改订单删除状态
     *
     * @param orderNo
     * @param status
     * @return
     */
    @Override
    public Integer updateOrderDelStatus(String orderNo, Integer status) {
        return orderInfoMapper.updateOrderDelStatus(orderNo, status);
    }

    @Override
    public Integer insertReturnId(OrderInfo orderInfo) {
        return orderInfoMapper.insertReturnId(orderInfo);
    }

//    /**
//     * 通过订单查询订单的退款金额
//     *
//     * @param orderInfo
//     * @return
//     */
//    @Override
//    public Integer getRefundAmount(OrderInfo orderInfo) {
//        Date nowDate = new Date();
//        Date checkIn = orderInfo.getCheckIn();
//        checkIn = DateUtils.afterHoursToDate(checkIn, 12L);
//        Integer refundAmount = orderInfo.getSnapshotTotalFee();
//        //如果当前时间大于等于入住时间，返回0，即不能退款
//        if (DateUtils.dateCompareDate(nowDate, checkIn)) {
//            refundAmount = 0;
//        }
//        //找出据入住时间6个小时前的时间
//        Date sixDate = DateUtils.afterHoursToDate(checkIn, -6L);
//        Integer roomId = orderInfo.getRoomId();
//        RoomInfo roomInfo = roomInfoMapper.selectByPrimaryKey(roomId);
//        if (roomInfo == null) {
//            throw new ServiceException("查询不到该订单所属房间");
//        }
//        HotelInfo hotelInfo = hotelInfoMapper.selectByPrimaryKey(roomInfo.getHotelId());
//        if (hotelInfo == null) {
//            throw new ServiceException("查询不到该订单所属酒店");
//        }
//        //获取距入住时间6个小时内的扣除比例(百分比)
//        Integer percent = getPercent(hotelInfo);
//        percent = 100 - percent;
//        if (DateUtils.dateCompareDate(nowDate, sixDate)) {
//            refundAmount = FormatUtils.amountToRate(refundAmount, percent);
//        }
//        //据入住时间6个小时外
//        return refundAmount;
//    }

    /**
     * 通过订单查询订单的退款金额
     *
     * @param orderInfo
     * @return
     */
    @Override
    public Integer getRefundAmount(OrderInfo orderInfo) {
        try {
            Date nowDate = new Date();
            Date checkIn = orderInfo.getCheckIn();
            checkIn = DateUtils.afterHoursToDate(checkIn, Long.valueOf(getCheckInHour()));
            Integer refundAmount = orderInfo.getSnapshotTotalFee();
            //18点之前全额退款，18点以后不能退款
            if (DateUtils.dateCompareDate(nowDate, checkIn)) {
                refundAmount = 0;
            }
            return refundAmount;
        } catch (Exception e) {
            log.info("获取订单退款金额失败{}", e.getLocalizedMessage());
            return 0;
        }
    }


    @Override
    public Integer updateByPrimaryKey(OrderInfo orderInfo) {

        return orderInfoMapper.updateByPrimaryKey(orderInfo);
    }

    /**
     * 用户确认订单
     *
     * @param userInfo
     * @param param
     * @param checkInDate
     * @param checkOutDate
     * @param count
     * @param remark
     * @param couponId
     * @param roomId
     * @param type
     * @return
     */
    @Transactional
    @Override
    public Map<String, String> preOrder(UserInfo userInfo, OrderInfo param, Long checkInDate, Long checkOutDate, Integer count, String remark, Integer couponId, Integer roomId, String type, String ip) {
        param.setUserId(userInfo.getId());
        param.setGmtCreate(new Date());
        param.setGmtModified(new Date());
        param.setStatus(OrderStatus.prePay);
        RoomInfo roomInfo = roomInfoService.selectByPrimaryKey(roomId);
        if (roomInfo == null) {
            throw new com.yeyks.exception.ServiceException("不能找到该房间的信息");
        }
        //获取今天的时间
        Date nowDate = DateUtils.localDateToDate(LocalDate.now());
        Date todayTime = roomInfo.getTodayTime();
        if (todayTime == null) {
            todayTime = nowDate;
            roomInfo.setTodayTime(todayTime);
            roomInfoMapper.updateIfNotNullByPrimaryKey(roomInfo);
        }
        if (nowDate.compareTo(todayTime) > 0) {
            roomInfo.setAvailable(roomInfo.getCount());
            roomInfo.setTodayTime(nowDate);
            roomInfoMapper.updateIfNotNullByPrimaryKey(roomInfo);
        }
        try {
            lock.readLock().lock();
            if (roomInfo.getAvailable() == null || roomInfo.getAvailable() <= 0) {
                throw new com.yeyks.exception.ServiceException("该房间暂无空房");
            }
            if (count != null && count != 0) {
                if (count > roomInfo.getAvailable()) {
                    throw new com.yeyks.exception.ServiceException("该房间仅剩" + roomInfo.getAvailable() + "间");
                }
            }
        } catch (Exception e) {
            log.error("确认订单时出错{}", e);
        } finally {
            lock.readLock().unlock();
        }
        HotelInfo hotelInfo = hotelService.selectHotelInfoById(roomInfo.getHotelId());
        if (hotelInfo == null) {
            throw new com.yeyks.exception.ServiceException("不能找到该酒店信息");
        }
        if (couponId != null && couponId != 0 && 0 == hotelInfo.getEnabledCoupon()) {
            throw new com.yeyks.exception.ServiceException("该酒店不支持优惠券");
        }
        param.setHotelId(hotelInfo.getId());
        param.setDeleteFlag(0);
        param.setRoomId(roomId);
        param.setPrice(roomInfo.getOrigPrice());
        param.setSnapshotHotelName(hotelInfo.getName());
        param.setSnapshotRoomName(roomInfo.getTitle());
        param.setSnapshotRoomPrice(roomInfo.getCurPrice());
        JSONObject hotelPrincipalObj = Utility.toJsonObject(hotelInfo.getPrincipalInfo());
        if (param.getCheckIn() == null) {
            param.setCheckIn(DateUtils.afterHoursToDate(DateUtils.stampToDate(checkInDate), 12L));
        }
        if (param.getCheckOut() == null) {
            param.setCheckOut(DateUtils.afterHoursToDate(DateUtils.stampToDate(checkOutDate), 12L));
        }
        Long days = DateUtils.getDayByBeginEnd(param.getCheckIn(), param.getCheckOut());
        if (roomInfo.getCurPrice() == null) {
            roomInfo.setCurPrice(0);
        }
        Integer totalFee = days.intValue() * roomInfo.getCurPrice();
        if (count != null && count != 0) {
            totalFee *= count;
        }
        // 优惠券使用逻辑
        int userCouponId = 0;
        if (couponId != null && couponId != 0) {
            List<Map> couponInfos = couponInfoService.selectByUser(userInfo.getId(), false, true, couponId);
            if (couponInfos == null || couponInfos.size() == 0) {
                log.info("通过券ID查询不到有效的券{}{}", userInfo.getId(), couponId);
                throw new ServiceException("券id不存在");
            }
            Map couponInfo = couponInfos.get(0);
            //validFee使用条件（分）
            Integer validFee = Integer.parseInt(couponInfo.get("valid_fee").toString());
            //price券值（分）
            Integer price = Integer.parseInt(couponInfo.get("price").toString());
            if (validFee > totalFee) {
                throw new ServiceException("不满足券的使用条件");
            }
            if (price > totalFee) {
                totalFee = 1;
            } else {
                totalFee -= price;
            }
            userCouponId = Integer.parseInt(couponInfo.get("userCoupon_id").toString());
        }
        if (totalFee <= 0) {
            totalFee = 1;
        }
        JSONObject orderExtraObject = Utility.toJsonObject(param.getExtraInfo());
        orderExtraObject.put("snapshot_hotel_address", hotelInfo.getAddress());
        orderExtraObject.put("snapshot_hotel_id", hotelInfo.getId());
        orderExtraObject.put("snapshot_hotel_phone", hotelPrincipalObj.getString("phone"));
        //获取该酒店所有人的账号
        AccountInfo accountInfo = accountInfoMapper.selectByPrimaryKey(hotelInfo.getOperatorId());
        if (accountInfo == null) {
            orderExtraObject.put("snapshot_tel_phone", hotelPrincipalObj.getString("phone"));
        } else {
            orderExtraObject.put("snapshot_tel_phone", accountInfo.getTel());
        }
        orderExtraObject.put("snapshot_pcinfo", accountService.getPrecentage());
        orderExtraObject.put("snapshot_totalfee", totalFee);
        orderExtraObject.put("snapshot_days", days);
        orderExtraObject.put("snapshot_count", count);
        orderExtraObject.put("remark", remark);
        if (userCouponId != 0) {
            orderExtraObject.put("couponId", userCouponId);
        } else {
            orderExtraObject.put("couponId", userCouponId);
        }
        param.setSnapshotTotalFee(totalFee);
        param.setExtraInfo(orderExtraObject.toJSONString());
        String orderNo = Utility.getOrderNo();
        param.setOrderNo(orderNo);
        log.info("将要生成的订单信息为{}", param);
        PreOrderInfo preOrderInfo = new PreOrderInfo();
        String payInfo = null;
        //支付宝
        if (type == null || type.equals(PayTypeEnum.ALIPAY.desc())) {
            payInfo = alipayService.tradeAppPay(orderNo, totalFee);
            param.setPaymentMethod(PayTypeEnum.ALIPAY.value());
            preOrderInfo.setAlipay(true);
        }
        //微信支付
        if (type != null && type.equals(PayTypeEnum.WXPAY.desc())) {
            payInfo = wxAppPayService.pay(totalFee, orderNo, ip);
            param.setPaymentMethod(PayTypeEnum.WXPAY.value());
        }
        int res = orderInfoMapper.insertReturnId(param);
        if (res != 1) {
            throw new com.yeyks.exception.ServiceException("生成订单失败");
        }
        preOrderInfo.setCount(count);
        preOrderInfo.setUserInfo(userInfo);
        preOrderInfo.setOrderInfo(param);
        preOrderInfo.setRoomInfo(roomInfo);
        preOrderInfo.setHotelInfo(hotelInfo);
        preOrderInfo.setDays(days);
        preOrderInfo.setAlipayInfo(payInfo);
        insertPreOrder(preOrderInfo);
        Map<String, String> map = new HashMap<>();
        map.put("orderNo", orderNo);
        map.put("payInfo", payInfo);
        return map;
    }
    @Transactional
    @Override
    public Map<String, String> preOrderV2(UserInfo userInfo, OrderInfo param, Long checkInDate, Long checkOutDate, Integer count, String remark, Integer couponId, Integer roomId, String type, String ip) {
        if (couponId == null) {
            couponId = 0;
        }
        param.setUserId(userInfo.getId());
        param.setGmtCreate(new Date());
        param.setGmtModified(new Date());
        param.setStatus(OrderStatus.prePay);
        RoomInfo roomInfo = roomInfoService.selectByPrimaryKey(roomId);
        if (roomInfo == null) {
            throw new com.yeyks.exception.ServiceException("不能找到该房间的信息");
        }
        //获取今天的时间
        Date nowDate = DateUtils.localDateToDate(LocalDate.now());
        Date todayTime = roomInfo.getTodayTime();
        if (todayTime == null) {
            todayTime = nowDate;
            roomInfo.setTodayTime(todayTime);
            roomInfoMapper.updateIfNotNullByPrimaryKey(roomInfo);
        }
        if (nowDate.compareTo(todayTime) > 0) {
            roomInfo.setAvailable(roomInfo.getCount());
            roomInfo.setTodayTime(nowDate);
            roomInfoMapper.updateIfNotNullByPrimaryKey(roomInfo);
        }
        try {
            lock.readLock().lock();
            if (roomInfo.getAvailable() == null || roomInfo.getAvailable() <= 0) {
                throw new com.yeyks.exception.ServiceException("该房间暂无空房");
            }
            if (count != null && count != 0) {
                if (count > roomInfo.getAvailable()) {
                    throw new com.yeyks.exception.ServiceException("该房间仅剩" + roomInfo.getAvailable() + "间");
                }
            }
        } catch (Exception e) {
            log.error("确认订单时出错{}", e);
        } finally {
            lock.readLock().unlock();
        }
        HotelInfo hotelInfo = hotelService.selectHotelInfoById(roomInfo.getHotelId());
        if (hotelInfo == null) {
            throw new com.yeyks.exception.ServiceException("不能找到该酒店信息");
        }
        if (couponId != 0 && 0 == hotelInfo.getEnabledCoupon()) {
            throw new com.yeyks.exception.ServiceException("该酒店不支持优惠券");
        }
        param.setHotelId(hotelInfo.getId());
        param.setDeleteFlag(0);
        param.setRoomId(roomId);
        param.setPrice(roomInfo.getOrigPrice());
        param.setSnapshotHotelName(hotelInfo.getName());
        param.setSnapshotRoomName(roomInfo.getTitle());
        param.setSnapshotRoomPrice(roomInfo.getCurPrice());
        JSONObject hotelPrincipalObj = Utility.toJsonObject(hotelInfo.getPrincipalInfo());
        if (param.getCheckIn() == null) {
            param.setCheckIn(DateUtils.afterHoursToDate(DateUtils.stampToDate(checkInDate), 12L));
        }
        if (param.getCheckOut() == null) {
            param.setCheckOut(DateUtils.afterHoursToDate(DateUtils.stampToDate(checkOutDate), 12L));
        }
        Long days = DateUtils.getDayByBeginEnd(param.getCheckIn(), param.getCheckOut());
        if (roomInfo.getCurPrice() == null) {
            roomInfo.setCurPrice(0);
        }
        Integer totalFee = days.intValue() * roomInfo.getCurPrice();
        if (count != null && count != 0) {
            totalFee *= count;
        }
        // 优惠券使用逻辑
        if (couponId != 0) {
            totalFee = useCoupon(userInfo.getId(), couponId, totalFee);
        }
        if (totalFee <= 0) {
            totalFee = 1;
        }
        JSONObject orderExtraObject = Utility.toJsonObject(param.getExtraInfo());
        orderExtraObject.put("snapshot_hotel_address", hotelInfo.getAddress());
        orderExtraObject.put("snapshot_hotel_id", hotelInfo.getId());
        orderExtraObject.put("snapshot_hotel_phone", hotelPrincipalObj.getString("phone"));
        //获取该酒店所有人的账号
        AccountInfo accountInfo = accountInfoMapper.selectByPrimaryKey(hotelInfo.getOperatorId());
        if (accountInfo == null) {
            orderExtraObject.put("snapshot_tel_phone", hotelPrincipalObj.getString("phone"));
        } else {
            orderExtraObject.put("snapshot_tel_phone", accountInfo.getTel());
        }
        orderExtraObject.put("snapshot_pcinfo", accountService.getPrecentage());
        orderExtraObject.put("snapshot_totalfee", totalFee);
        orderExtraObject.put("snapshot_days", days);
        orderExtraObject.put("snapshot_count", count);
        orderExtraObject.put("remark", remark);
        if (couponId != 0) {
            orderExtraObject.put("couponId", couponId);
        } else {
            orderExtraObject.put("couponId", couponId);
        }
        param.setSnapshotTotalFee(totalFee);
        param.setExtraInfo(orderExtraObject.toJSONString());
        String orderNo = Utility.getOrderNo();
        param.setOrderNo(orderNo);
        log.info("将要生成的订单信息为{}", param);
        PreOrderInfo preOrderInfo = new PreOrderInfo();
        String payInfo = null;
        //支付宝
        if (type == null || type.equals(PayTypeEnum.ALIPAY.desc())) {
            payInfo = alipayService.tradeAppPay(orderNo, totalFee);
            param.setPaymentMethod(PayTypeEnum.ALIPAY.value());
            preOrderInfo.setAlipay(true);
        }
        //微信支付
        if (type != null && type.equals(PayTypeEnum.WXPAY.desc())) {
            payInfo = wxAppPayService.pay(totalFee, orderNo, ip);
            param.setPaymentMethod(PayTypeEnum.WXPAY.value());
        }
        int res = orderInfoMapper.insertReturnId(param);
        if (res != 1) {
            throw new com.yeyks.exception.ServiceException("生成订单失败");
        }
        preOrderInfo.setCount(count);
        preOrderInfo.setUserInfo(userInfo);
        preOrderInfo.setOrderInfo(param);
        preOrderInfo.setRoomInfo(roomInfo);
        preOrderInfo.setHotelInfo(hotelInfo);
        preOrderInfo.setDays(days);
        preOrderInfo.setAlipayInfo(payInfo);
        insertPreOrder(preOrderInfo);
        Map<String, String> map = new HashMap<>();
        map.put("orderNo", orderNo);
        map.put("payInfo", payInfo);
        return map;
    }

    private Integer useCoupon(Integer userId, Integer couponId, Integer totalFee) {
        try {
            UserCouponInfo userCouponInfo = userCouponInfoMapper.selectByPrimaryKey(couponId);
            if (userCouponInfo == null) {
                throw new ServiceException("该用户券不存在");
            }
            if (!userId.equals(userCouponInfo.getUserId())) {
                throw new ServiceException("非本人优惠券");
            }
            if (DateUtils.dateCompareDate(new Date(), userCouponInfo.getOverTime())) {
                throw new ServiceException("该优惠券已过期");
            }
            if (userCouponInfo.getUsed()) {//true已使用
                throw new ServiceException("该优惠券已使用");
            }
            CouponInfo couponInfo = couponInfoService.selectByCouponId(userCouponInfo.getCouponId());
            if (couponInfo == null) {
                throw new ServiceException("该券不存在");
            }
            if (couponInfo.getType() != null) {
                if (couponInfo.getType().equals(CouponConst.recommend)
                        || couponInfo.getType().equals(CouponConst.free)) {
                    couponInfo.setPrice(userCouponInfo.getCouponValue());
                }
            }
            //validFee使用条件（分）
            Integer validFee = couponInfo.getValidFee();
            //price券值（分）
            Integer price = couponInfo.getPrice();
            if (validFee > totalFee) {
                throw new ServiceException("不满足券的使用条件");
            }
            if (price > totalFee) {
                totalFee = 1;
            } else {
                totalFee -= price;
            }
            return totalFee;
        } catch (ServiceException e) {
            throw new ServiceException(e.getMessage());
        } catch (Exception e) {
            log.error("使用券异常{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
        return totalFee;
    }

    /**
     * h5用户确认订单
     *
     * @param userInfo
     * @param param
     * @param checkInDate
     * @param checkOutDate
     * @param count
     * @param remark
     * @param couponId
     * @param roomId
     * @param type
     * @param ip
     * @param openId
     * @param flag
     * @return
     */
    @Transactional
    @Override
    public Map<String, String> h5PreOrder(UserInfo userInfo, OrderInfo param, Long checkInDate, Long checkOutDate, Integer count, String remark, Integer couponId, Integer roomId, String type, String ip, String openId, Boolean flag) {
        if (couponId == null) {
            couponId = 0;
        }
        param.setUserId(userInfo.getId());
        param.setGmtCreate(new Date());
        param.setGmtModified(new Date());
        param.setStatus(OrderStatus.prePay);
        RoomInfo roomInfo = roomInfoService.selectByPrimaryKey(roomId);
        if (roomInfo == null) {
            throw new com.yeyks.exception.ServiceException("不能找到该房间的信息");
        }
        //获取今天的时间
        Date nowDate = DateUtils.localDateToDate(LocalDate.now());
        Date todayTime = roomInfo.getTodayTime();
        if (todayTime == null) {
            todayTime = nowDate;
            roomInfo.setTodayTime(todayTime);
            roomInfoMapper.updateIfNotNullByPrimaryKey(roomInfo);
        }
        if (nowDate.compareTo(todayTime) > 0) {
            roomInfo.setAvailable(roomInfo.getCount());
            roomInfo.setTodayTime(nowDate);
            roomInfoMapper.updateIfNotNullByPrimaryKey(roomInfo);
        }
        try {
            lock.readLock().lock();
            if (roomInfo.getAvailable() == null || roomInfo.getAvailable() <= 0) {
                throw new com.yeyks.exception.ServiceException("该房间暂无空房");
            }
            if (count != null && count != 0) {
                if (count > roomInfo.getAvailable()) {
                    throw new com.yeyks.exception.ServiceException("该房间仅剩" + roomInfo.getAvailable() + "间");
                }
            }
        } catch (Exception e) {
            log.error("确认订单时出错{}", e);
        } finally {
            lock.readLock().unlock();
        }
        HotelInfo hotelInfo = hotelService.selectHotelInfoById(roomInfo.getHotelId());
        if (hotelInfo == null) {
            throw new com.yeyks.exception.ServiceException("不能找到该酒店信息");
        }
        if (couponId != 0 && 0 == hotelInfo.getEnabledCoupon()) {
            throw new com.yeyks.exception.ServiceException("该酒店不支持优惠券");
        }
        param.setHotelId(hotelInfo.getId());
        param.setDeleteFlag(0);
        param.setRoomId(roomId);
        param.setPrice(roomInfo.getOrigPrice());
        param.setSnapshotHotelName(hotelInfo.getName());
        param.setSnapshotRoomName(roomInfo.getTitle());
        param.setSnapshotRoomPrice(roomInfo.getCurPrice());
        JSONObject hotelPrincipalObj = Utility.toJsonObject(hotelInfo.getPrincipalInfo());
        if (param.getCheckIn() == null) {
            param.setCheckIn(DateUtils.afterHoursToDate(DateUtils.stampToDate(checkInDate), 12L));
        }
        if (param.getCheckOut() == null) {
            param.setCheckOut(DateUtils.afterHoursToDate(DateUtils.stampToDate(checkOutDate), 12L));
        }
        Long days = DateUtils.getDayByBeginEnd(param.getCheckIn(), param.getCheckOut());
        if (roomInfo.getCurPrice() == null) {
            roomInfo.setCurPrice(0);
        }
        Integer totalFee = days.intValue() * roomInfo.getCurPrice();
        if (count != null && count != 0) {
            totalFee *= count;
        }
        // 优惠券使用逻辑
        if (couponId != 0) {
            totalFee = useCoupon(userInfo.getId(), couponId, totalFee);
//            List<Map> couponInfos = couponInfoService.selectByUser(userInfo.getId(), false, true, couponId);
//            if (couponInfos == null || couponInfos.size() == 0) {
//                log.info("通过券ID查询不到有效的券{}{}", userInfo.getId(), couponId);
//                throw new ServiceException("券id不存在");
//            }
//            Map couponInfo = couponInfos.get(0);
//            //validFee使用条件（分）
//            Integer validFee = Integer.parseInt(couponInfo.get("valid_fee").toString());
//            //price券值（分）
//            Integer price = Integer.parseInt(couponInfo.get("price").toString());
//            if (validFee != 0 && validFee > totalFee) {
//                throw new ServiceException("不满足券的使用条件");
//            }
//
//            if (price > totalFee) {
//                totalFee = 1;
//            } else {
//                totalFee -= price;
//            }
//            userCouponId = Integer.parseInt(couponInfo.get("userCoupon_id").toString());
        }
        if (totalFee <= 0) {
            totalFee = 1;
        }
        JSONObject orderExtraObject = Utility.toJsonObject(param.getExtraInfo());
        orderExtraObject.put("snapshot_hotel_address", hotelInfo.getAddress());
        orderExtraObject.put("snapshot_hotel_id", hotelInfo.getId());
        orderExtraObject.put("snapshot_hotel_phone", hotelPrincipalObj.getString("phone"));
        //获取该酒店所有人的账号
        AccountInfo accountInfo = accountInfoMapper.selectByPrimaryKey(hotelInfo.getOperatorId());
        if (accountInfo == null) {
            orderExtraObject.put("snapshot_tel_phone", hotelPrincipalObj.getString("phone"));
        } else {
            orderExtraObject.put("snapshot_tel_phone", accountInfo.getTel());
        }
        orderExtraObject.put("snapshot_pcinfo", accountService.getPrecentage());
        orderExtraObject.put("snapshot_totalfee", totalFee);
        orderExtraObject.put("snapshot_days", days);
        orderExtraObject.put("snapshot_count", count);
        orderExtraObject.put("remark", remark);
        if (couponId != 0) {
            orderExtraObject.put("couponId", couponId);
        } else {
            orderExtraObject.put("couponId", couponId);
        }
        param.setSnapshotTotalFee(totalFee);
        param.setExtraInfo(orderExtraObject.toJSONString());
        String orderNo = Utility.getOrderNo();
        param.setOrderNo(orderNo);
        log.info("将要生成的订单信息为{}", param);
        PreOrderInfo preOrderInfo = new PreOrderInfo();
        //JSAPI支付
        Map<String, String> wxPayInfo;
        try {
            Utility.switchConfig(flag, payService.getEngine(), null);
            wxPayInfo = payService.wxPreOrder(
                    openId, "商品描述", totalFee, orderNo, ip,
                    oldNotifyUrl,
                    "JSAPI");
        } catch (Exception e) {
            log.info("微信JSAPI支付异常{}", Arrays.toString(e.getStackTrace()));
            throw new ServiceException("支付异常");
        }
        if (type == null || type.equals(PayTypeEnum.XCX.desc())) {
            param.setPaymentMethod(PayTypeEnum.XCX.value());
        }
        if (type != null && type.equals(PayTypeEnum.GZH.desc())) {
            param.setPaymentMethod(PayTypeEnum.GZH.value());
        }
        int res = orderInfoMapper.insertReturnId(param);
        if (res != 1) {
            throw new com.yeyks.exception.ServiceException("生成订单失败");
        }
        preOrderInfo.setCount(count);
        preOrderInfo.setUserInfo(userInfo);
        preOrderInfo.setOrderInfo(param);
        preOrderInfo.setRoomInfo(roomInfo);
        preOrderInfo.setHotelInfo(hotelInfo);
        preOrderInfo.setDays(days);
        insertPreOrder(preOrderInfo);
        wxPayInfo.put("orderNo", param.getOrderNo());
        return wxPayInfo;
    }

//    /**
//     * h5用户确认订单
//     *
//     * @param userInfo
//     * @param param
//     * @param checkInDate
//     * @param checkOutDate
//     * @param count
//     * @param remark
//     * @param couponId
//     * @param roomId
//     * @param type
//     * @param ip
//     * @param openId
//     * @param flag
//     * @return
//     */
//    @Transactional
//    @Override
//    public Map<String, String> h5PreOrderV2(UserInfo userInfo, OrderInfo param, Long checkInDate, Long checkOutDate, Integer count, String remark, Integer couponId, Integer roomId, String type, String ip, String openId, Boolean flag) {
//        param.setUserId(userInfo.getId());
//        param.setGmtCreate(new Date());
//        param.setGmtModified(new Date());
//        param.setStatus(OrderStatus.prePay);
//        RoomInfo roomInfo = roomInfoService.selectByPrimaryKey(roomId);
//        if (roomInfo == null) {
//            throw new com.yeyks.exception.ServiceException("不能找到该房间的信息");
//        }
//        //获取今天的时间
//        Date nowDate = DateUtils.localDateToDate(LocalDate.now());
//        Date todayTime = roomInfo.getTodayTime();
//        if (todayTime == null) {
//            todayTime = nowDate;
//            roomInfo.setTodayTime(todayTime);
//            roomInfoMapper.updateIfNotNullByPrimaryKey(roomInfo);
//        }
//        if (nowDate.compareTo(todayTime) > 0) {
//            roomInfo.setAvailable(roomInfo.getCount());
//            roomInfo.setTodayTime(nowDate);
//            roomInfoMapper.updateIfNotNullByPrimaryKey(roomInfo);
//        }
//        try {
//            lock.readLock().lock();
//            if (roomInfo.getAvailable() == null || roomInfo.getAvailable() <= 0) {
//                throw new com.yeyks.exception.ServiceException("该房间暂无空房");
//            }
//            if (count != null && count != 0) {
//                if (count > roomInfo.getAvailable()) {
//                    throw new com.yeyks.exception.ServiceException("该房间仅剩" + roomInfo.getAvailable() + "间");
//                }
//            }
//        } catch (Exception e) {
//            log.error("确认订单时出错{}", e);
//        } finally {
//            lock.readLock().unlock();
//        }
//        HotelInfo hotelInfo = hotelService.selectHotelInfoById(roomInfo.getHotelId());
//        if (hotelInfo == null) {
//            throw new com.yeyks.exception.ServiceException("不能找到该酒店信息");
//        }
//        param.setHotelId(hotelInfo.getId());
//        param.setDeleteFlag(0);
//        param.setRoomId(roomId);
//        param.setPrice(roomInfo.getOrigPrice());
//        param.setSnapshotHotelName(hotelInfo.getName());
//        param.setSnapshotRoomName(roomInfo.getTitle());
//        param.setSnapshotRoomPrice(roomInfo.getCurPrice());
//        JSONObject hotelPrincipalObj = Utility.toJsonObject(hotelInfo.getPrincipalInfo());
//        if (param.getCheckIn() == null) {
//            param.setCheckIn(DateUtils.afterHoursToDate(DateUtils.stampToDate(checkInDate), 12L));
//        }
//        if (param.getCheckOut() == null) {
//            param.setCheckOut(DateUtils.afterHoursToDate(DateUtils.stampToDate(checkOutDate), 12L));
//        }
//        Long days = DateUtils.getDayByBeginEnd(param.getCheckIn(), param.getCheckOut());
//        if (roomInfo.getCurPrice() == null) {
//            roomInfo.setCurPrice(0);
//        }
//        Integer totalFee = days.intValue() * roomInfo.getCurPrice();
//        if (count != null && count != 0) {
//            totalFee *= count;
//        }
//        // 优惠券使用逻辑
//        int userCouponId = 0;
//        if (couponId != null && couponId != 0) {
//            List<Map> couponInfos = couponInfoService.selectByUser(userInfo.getId(), false, true, couponId);
//            if (couponInfos == null || couponInfos.size() == 0) {
//                log.info("通过券ID查询不到有效的券{}{}", userInfo.getId(), couponId);
//                throw new ServiceException("券id不存在");
//            }
//            Map couponInfo = couponInfos.get(0);
//            int couponType = Integer.parseInt(couponInfo.get("type").toString());
//            if (CouponConst.free == couponType) {//免单券最多免单200
//                if (totalFee <= 20000) {
//                    totalFee = 1;
//                } else {
//                    totalFee -= 20000;
//                }
//            } else {
//                //validFee使用条件（分）
//                Integer validFee = Integer.parseInt(couponInfo.get("valid_fee").toString());
//                //price券值（分）
//                Integer price = Integer.parseInt(couponInfo.get("price").toString());
//                if (validFee != 0 && validFee > totalFee) {
//                    throw new ServiceException("不满足券的使用条件");
//                }
//
//                if (price > totalFee) {
//                    totalFee = 1;
//                } else {
//                    totalFee -= price;
//                }
//            }
//            userCouponId = Integer.parseInt(couponInfo.get("userCoupon_id").toString());
//        }
//        if (totalFee <= 0) {
//            totalFee = 1;
//        }
//        JSONObject orderExtraObject = Utility.toJsonObject(param.getExtraInfo());
//        orderExtraObject.put("snapshot_hotel_address", hotelInfo.getAddress());
//        orderExtraObject.put("snapshot_hotel_id", hotelInfo.getId());
//        orderExtraObject.put("snapshot_hotel_phone", hotelPrincipalObj.getString("phone"));
//        //获取该酒店所有人的账号
//        AccountInfo accountInfo = accountInfoMapper.selectByPrimaryKey(hotelInfo.getOperatorId());
//        if (accountInfo == null) {
//            orderExtraObject.put("snapshot_tel_phone", hotelPrincipalObj.getString("phone"));
//        } else {
//            orderExtraObject.put("snapshot_tel_phone", accountInfo.getTel());
//        }
//        orderExtraObject.put("snapshot_pcinfo", accountService.getPrecentage());
//        orderExtraObject.put("snapshot_totalfee", totalFee);
//        orderExtraObject.put("snapshot_days", days);
//        orderExtraObject.put("snapshot_count", count);
//        orderExtraObject.put("remark", remark);
//        if (userCouponId != 0) {
//            orderExtraObject.put("couponId", userCouponId);
//        } else {
//            orderExtraObject.put("couponId", userCouponId);
//        }
//        param.setSnapshotTotalFee(totalFee);
//        param.setExtraInfo(orderExtraObject.toJSONString());
//        String orderNo = Utility.getOrderNo();
//        param.setOrderNo(orderNo);
//        log.info("将要生成的订单信息为{}", param);
//        PreOrderInfo preOrderInfo = new PreOrderInfo();
//        //JSAPI支付
//        Map<String, String> wxPayInfo = null;
//        try {
//            wxPayInfo = wxLoginService.unifiedOrderOld(type, openId, "商品描述", totalFee, orderNo, ip, oldNotifyUrl, "JSAPI");
//        } catch (Exception e) {
//            log.info("微信JSAPI支付异常{}", Arrays.toString(e.getStackTrace()));
//            throw new ServiceException("支付异常");
//        }
//        if (type == null || type.equals(PayTypeEnum.XCX.desc())) {
//            param.setPaymentMethod(PayTypeEnum.XCX.value());
//        }
//        if (type != null && type.equals(PayTypeEnum.GZH.desc())) {
//            param.setPaymentMethod(PayTypeEnum.GZH.value());
//        }
//        int res = orderInfoMapper.insertReturnId(param);
//        if (res != 1) {
//            throw new com.yeyks.exception.ServiceException("生成订单失败");
//        }
//        preOrderInfo.setCount(count);
//        preOrderInfo.setUserInfo(userInfo);
//        preOrderInfo.setOrderInfo(param);
//        preOrderInfo.setRoomInfo(roomInfo);
//        preOrderInfo.setHotelInfo(hotelInfo);
//        preOrderInfo.setDays(days);
//        insertPreOrder(preOrderInfo);
//        wxPayInfo.put("orderNo", param.getOrderNo());
//        return wxPayInfo;
//    }

    /**
     * 用户去支付
     *
     * @param userInfo
     * @param orderNo
     * @param type
     * @return
     */
    @Override
    public Map<String, String> goPay(UserInfo userInfo, String orderNo, String type, String ip) {
        //通过订单号查询订单
        OrderInfo orderInfo = orderInfoMapper.selectByOrderNo(orderNo);
        checkOrderInfo(userInfo, orderInfo);
        //检查券是否可用
        checkCoupon(orderInfo);
        Integer roomId = orderInfo.getRoomId();
        //获取订购的房间个数
        Integer count = getCount(orderInfo);
        RoomInfo roomInfo = roomInfoService.selectByPrimaryKey(roomId);
        if (roomInfo == null) {
            throw new com.yeyks.exception.ServiceException("不能找到该房间的信息");
        }
        if (roomInfo.getAvailable() <= 0) {
            throw new com.yeyks.exception.ServiceException("该房间暂无空房");
        }
        if (count != null && count != 0) {
            if (count > roomInfo.getAvailable()) {
                throw new com.yeyks.exception.ServiceException("该房间仅剩" + roomInfo.getAvailable() + "间");
            }
        }
        PreOrderInfo preOrderInfo = new PreOrderInfo();
        String payInfo = null;
        //支付宝
        if (type == null || type.equals(PayTypeEnum.ALIPAY.desc())) {
            payInfo = alipayService.tradeAppPay(orderInfo.getOrderNo(), orderInfo.getSnapshotTotalFee());
            orderInfo.setPaymentMethod(PayTypeEnum.ALIPAY.value());
            preOrderInfo.setAlipay(true);
        }
        //微信支付
        if (type != null && type.equals(PayTypeEnum.WXPAY.desc())) {
            payInfo = wxAppPayService.pay(orderInfo.getSnapshotTotalFee(), orderNo, ip);
            orderInfo.setPaymentMethod(PayTypeEnum.WXPAY.value());
        }
        preOrderInfo.setCount(count);
        preOrderInfo.setUserInfo(userInfo);
        preOrderInfo.setOrderInfo(orderInfo);
        preOrderInfo.setRoomInfo(roomInfo);
        preOrderInfo.setHotelInfo(hotelService.selectHotelInfoById(roomInfo.getHotelId()));
        preOrderInfo.setDays(getDays(orderInfo));
        preOrderInfo.setAlipayInfo(payInfo);
        insertPreOrder(preOrderInfo);

        Map<String, String> map = new HashMap<>();
        map.put("payInfo", payInfo);
        return map;
    }

    /**
     * h5用户去支付
     *
     * @param userInfo
     * @param orderNo
     * @param type
     * @param ip
     * @param openId
     * @param flag
     * @return
     */
    @Transactional
    @Override
    public Map<String, String> h5GoPay(UserInfo userInfo, String orderNo, String type, String ip, String openId, Boolean flag) {
        OrderInfo orderInfo;
        //通过订单号查询订单
        OrderInfo existOrderInfo = orderInfoMapper.selectByOrderNo(orderNo);
        checkOrderInfo(userInfo, existOrderInfo);
        //查询原来的支付方式
        String origType = PayTypeEnum.getDescByValue(existOrderInfo.getPaymentMethod());
        //支付方式不同的话需要重新生成订单号
        if (!type.equals(origType)) {
            String neworderNo = Utility.getOrderNo();
            orderInfo = getOrderInfo(neworderNo, existOrderInfo);
            //将原来的订单修改为已删除状态
            orderInfoMapper.updateOrderStatus(orderNo, OrderStatus.delete);
        } else {//支付方式相等不处理
            orderInfo = existOrderInfo;
        }
        //检查券是否可用
        checkCoupon(orderInfo);
        Integer roomId = orderInfo.getRoomId();
        //获取订购的房间个数
        Integer count = getCount(orderInfo);
        RoomInfo roomInfo = roomInfoService.selectByPrimaryKey(roomId);
        if (roomInfo == null) {
            throw new com.yeyks.exception.ServiceException("不能找到该房间的信息");
        }
        if (roomInfo.getAvailable() <= 0) {
            throw new com.yeyks.exception.ServiceException("该房间暂无空房");
        }
        if (count != null && count != 0) {
            if (count > roomInfo.getAvailable()) {
                throw new com.yeyks.exception.ServiceException("该房间仅剩" + roomInfo.getAvailable() + "间");
            }
        }
        PreOrderInfo preOrderInfo = new PreOrderInfo();
        //JSAPI支付
        Map<String, String> wxPayInfo;
        try {
            Utility.switchConfig(flag, payService.getEngine(), null);
            wxPayInfo = payService.wxPreOrder(
                    openId, "商品描述", orderInfo.getSnapshotTotalFee(), orderInfo.getOrderNo(), ip,
                    oldNotifyUrl,
                    "JSAPI");
        } catch (Exception e) {
            log.info("微信JSAPI支付异常{}", Arrays.toString(e.getStackTrace()));
            throw new ServiceException("支付异常");
        }
        if (type.equals(PayTypeEnum.XCX.desc())) {
            orderInfo.setPaymentMethod(PayTypeEnum.XCX.value());
        }
        if (type.equals(PayTypeEnum.GZH.desc())) {
            orderInfo.setPaymentMethod(PayTypeEnum.GZH.value());
        }
        if (!type.equals(origType)) {
            Integer res = orderInfoMapper.insertReturnId(orderInfo);
            if (res != 1) {
                throw new com.yeyks.exception.ServiceException("h5去支付生成订单失败");
            }
        }
        preOrderInfo.setCount(count);
        preOrderInfo.setUserInfo(userInfo);
        preOrderInfo.setOrderInfo(orderInfo);
        preOrderInfo.setRoomInfo(roomInfo);
        preOrderInfo.setHotelInfo(hotelService.selectHotelInfoById(roomInfo.getHotelId()));
        preOrderInfo.setDays(getDays(orderInfo));
        insertPreOrder(preOrderInfo);
        return wxPayInfo;
    }

    /**
     * 查询订单详情
     *
     * @param orderInfo
     * @return
     */
    @Override
    public OrderDetailDTO detail(OrderInfo orderInfo) {
        RoomInfo roomInfo = roomInfoService.selectByPrimaryKey(orderInfo.getRoomId());
        if (roomInfo == null) {
            throw new ServiceException("该订单所属房间不存在");
        }
        HotelInfo hotelInfo = hotelService.selectHotelInfoById(roomInfo.getHotelId());
        if (hotelInfo == null) {
            throw new ServiceException("该订单所属酒店不存在");
        }
        OrderDetailDTO detailDTO = ObjectConvertUtil.convertObject(orderInfo, OrderDetailDTO.class);
        Long days = DateUtils.getDayByBeginEnd(orderInfo.getCheckIn(), orderInfo.getCheckOut());
        detailDTO.setDays(days.intValue());
        detailDTO.setCount(getCount(orderInfo) == null ? 0 : getCount(orderInfo));
        Map<String, String> map = getNamePhone(orderInfo);
        detailDTO.setName(map.get("name"));
        detailDTO.setPhone(map.get("phone"));
        detailDTO.setArea(roomInfo.getArea());
        detailDTO.setDevices(roomInfo.getDevices());
        detailDTO.setDevicesCn(roomInfo.getDevicesCn());
        detailDTO.setMaxPeople(roomInfo.getMaxPeople());
        detailDTO.setOrigPrice(roomInfo.getOrigPrice() == null ? 0 : roomInfo.getOrigPrice());
        detailDTO.setRoomId(roomInfo.getId());
        detailDTO.setRoomName(roomInfo.getTitle());
        detailDTO.setHotelId(hotelInfo.getId());
        detailDTO.setHotelAddress(hotelInfo.getAddress());
        detailDTO.setHotelName(hotelInfo.getName());
        detailDTO.setPositionX(hotelInfo.getPositionX());
        detailDTO.setPositionY(hotelInfo.getPositionY());
        detailDTO.setTel(hotelService.getTelByHotelInfo(hotelInfo));
        detailDTO.setBedType(roomInfo.getBedType());
        detailDTO.setBedTypeCn(roomInfo.getBedTypeCn());
        detailDTO.setPrice(getPrice(orderInfo));
        detailDTO.setCurPrice(roomInfo.getCurPrice() == null ? 0 : roomInfo.getCurPrice());
        JSONObject jsonObject = JSONObject.parseObject(roomInfo.getExtraInfo());
        if (jsonObject != null) {
            detailDTO.setPicUrls((List<String>) jsonObject.get("imgUrlList"));
        }
        detailDTO.setTotalPrice(detailDTO.getDays() * detailDTO.getCount() * detailDTO.getCurPrice());
        return detailDTO;
    }

    /**
     * 通过订单获取该订单使用的券的满减金额
     *
     * @param orderInfo
     * @return
     */
    public Integer getPrice(OrderInfo orderInfo) {
        try {
            String extraInfo = orderInfo.getExtraInfo();
            JSONObject jsonObject = JSONObject.parseObject(extraInfo);
            Integer couponId = (Integer) jsonObject.get("couponId");
            if (couponId == null || couponId == 0) {
                return null;
            } else {
                UserCouponInfo userCouponInfo = userCouponService.selectUserCouponById(couponId);
                CouponInfo couponInfo = couponInfoService.selectByCouponId(userCouponInfo == null ? null : userCouponInfo.getCouponId());
                if (couponInfo == null) {
                    return null;
                } else {
                    if (couponInfo.getType() != null) {
                        if (couponInfo.getType().equals(CouponConst.free)
                                || couponInfo.getType().equals(CouponConst.recommend)) {
                            couponInfo.setPrice(userCouponInfo == null ? 0 : userCouponInfo.getCouponValue());
                        }
                    }
                    return couponInfo.getPrice();
                }
            }
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 通过订单号查询改订单的状态，为未支付则修改为已取消
     *
     * @param orderNo
     * @return
     */
    @Override
    public Integer updateCancleOrder(String orderNo) {
        OrderInfo orderInfo = orderInfoMapper.selectByOrderNo(orderNo);
        if (orderInfo == null) {
            return null;
        }
        int res = 0;
        if (orderInfo.getStatus() != null) {
            if (orderInfo.getStatus().equals(OrderStatus.prePay)) {
                orderInfo.setStatus(OrderStatus.cancle);
                res = orderInfoMapper.updateByPrimaryKey(orderInfo);
            } else {
                res = -1;
            }

        }
        return res;
    }

    private Map<String, String> getNamePhone(OrderInfo orderInfo) {
        Map<String, String> map = new HashMap<>();
        try {
            String info = orderInfo.getVitalPersonInfo();
            JSONObject jsonObject = JSONObject.parseObject(info);
            map.put("name", (String) jsonObject.get("name"));
            map.put("phone", (String) jsonObject.get("phone"));
        } catch (Exception e) {
            map.put("name", null);
            map.put("phone", null);
        }
        return map;
    }

    private OrderInfo getOrderInfo(String neworderNo, OrderInfo existOrderInfo) {
        OrderInfo orderInfo = ObjectConvertUtil.convertObject(existOrderInfo, OrderInfo.class);
        orderInfo.setOrderNo(neworderNo);
        return orderInfo;
    }

    private void checkCoupon(OrderInfo orderInfo) {
        JSONObject jsonObject = JSONObject.parseObject(orderInfo.getExtraInfo());
        Integer couponId = (Integer) jsonObject.get("couponId");
        UserCouponInfo userCouponInfo = userCouponService.selectUserCouponById(couponId);
        if (userCouponInfo == null) {
            return;
        }
        if (userCouponInfo.getUsed().equals(true)) {
            throw new ServiceException("该订单对应优惠券已被使用");
        }
        if (DateUtils.dateCompareDate(new Date(), userCouponInfo.getOverTime())) {
            throw new ServiceException("该订单对应优惠券已过期");
        }
    }

    /**
     * 用户评分
     *
     * @param orderNo
     * @param score
     * @return
     */
    @Override
    public Integer updateScoreByOrderNo(String orderNo, Integer score) {
        return orderInfoMapper.updateScoreByOrderNo(orderNo, score);

    }

    /**
     * 更新用户评分和状态
     *
     * @param orderNo
     * @param score
     * @param status
     * @return
     */
    @Override
    public Integer updateScoreAndStatusByOrderNo(String orderNo, Integer score, Integer status) {
        return orderInfoMapper.updateScoreAndStatusByOrderNo(orderNo, score, status);
    }

    /**
     * 通过订单号查询该订单对应的酒店id
     *
     * @param orderNo
     * @return
     */
    @Override
    public Integer getHotelIdByOrderNo(String orderNo) {
        return orderInfoMapper.getHotelIdByOrderNo(orderNo);
    }

    private Integer getDays(OrderInfo orderInfo) {
        JSONObject jsonObject = JSONObject.parseObject(orderInfo.getExtraInfo());
        return (Integer) jsonObject.get("snapshot_days");
    }

    private Integer getCount(OrderInfo orderInfo) {
        JSONObject jsonObject = JSONObject.parseObject(orderInfo.getExtraInfo());
        return (Integer) jsonObject.get("snapshot_count");
    }

    private void checkOrderInfo(UserInfo userInfo, OrderInfo orderInfo) {
        if (orderInfo == null) {
            throw new ServiceException("该订单不存在");
        }
        if (!orderInfo.getStatus().equals(OrderStatus.prePay)) {
            throw new ServiceException("该订单非待支付状态");
        }
        if (!orderInfo.getUserId().equals(userInfo.getId())) {
            throw new ServiceException("当前订单非本人");
        }
    }

    private Integer getPercent(HotelInfo hotelInfo) {
        String refundCfg = hotelInfo.getRefundCfg();
        JSONObject map = JSONObject.parseObject(refundCfg);
        Integer six = (Integer) map.get("6");
        return six * 100 / 1000;
    }
}